#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N=100005;
struct Node{
    int l,r;
    LL sum,plz,mlz;
    Node* left;
    Node* right;
    Node(int l_,int r_){
        l=l_;r=r_;
        sum=plz=0;
        mlz=1;
        left=right=nullptr;
    }
};
LL arr[N],ans;
int n,q,m;

Node* build(int l,int r){
    Node* root=new Node{l,r};
    if(l==r){
        root->sum=arr[l]%m;
        return root;
    }
    int mid=(r-l)/2+l;
    root->left=build(l,mid);
    root->right=build(mid+1,r);
    root->sum=(root->left->sum+root->right->sum)%m;
    return root;
}
void pushdown(Node* root){
    if(!(root->plz==0&&root->mlz==1)){
        int l=root->l,r=root->r;
        int mid=(r-l)/2+l;
        LL k1=root->mlz,k2=root->plz;
        root->left->sum=(root->left->sum*k1+k2*(mid-l+1))%m;
        root->right->sum=(root->right->sum*k1+k2*(r-mid))%m;
        root->left->mlz=(root->left->mlz*k1)%m;
        root->right->mlz=(root->right->mlz*k1)%m;
        root->left->plz=(root->left->plz*k1+k2)%m;
        root->right->plz=(root->right->plz*k1+k2)%m;
        //
        root->plz=0;
        root->mlz=1;
    }
    return;
}
void add(Node* root,const int x,const int y,const LL k){
    int l=root->l,r=root->r;
    if(!root||l>y||r<x) return;
    if(x<=l&&r<=y){
        root->plz=(root->plz+k)%m;
        root->sum=(root->sum+k*(r-l+1) )%m;
        return;
    }
    pushdown(root);
    int mid=(r-l)/2+l;
    if(mid>=x) add(root->left,x,y,k);
    if(mid<y) add(root->right,x,y,k);
    root->sum=(root->left->sum+root->right->sum)%m;
    return;
}

void mul(Node* root,const int x,const int y,const LL k){
    int l=root->l,r=root->r;
    if(!root||l>y||r<x) return;
    if(x<=l&&r<=y){
        root->mlz=(root->mlz*k)%m;
        root->plz=(root->plz*k)%m;
        root->sum=(root->sum*k)%m;
        return;
    }
    pushdown(root);
    int mid=(r-l)/2+l;
    if(mid>=x) mul(root->left,x,y,k);
    if(mid<y) mul(root->right,x,y,k);
    root->sum=(root->left->sum+root->right->sum)%m;
    return;
}
void query(Node* root,const int x,const int y){
    int l=root->l,r=root->r;
    if(!root||l>y||r<x) return;
    if(x<=l&&r<=y){
        ans=(ans+root->sum)%m;
        return;
    }
    pushdown(root);
    int mid=(r-l)/2+l;
    if(mid>=x) query(root->left,x,y);
    if(mid<y) query(root->right,x,y);
    return;
}

int main(){
    scanf("%d%d%d",&n,&q,&m);
    for(int i=1;i<=n;i++){
        scanf("%d",&arr[i]);
    }
    Node* root=build(1,n);
    int op,x,y;
    LL k;
    for(int i=0;i<q;i++){
        scanf("%d",&op);
        if(op==1){
            scanf("%d%d%lld",&x,&y,&k);
            mul(root,x,y,k);
        }
        else if(op==2){
            scanf("%d%d%lld",&x,&y,&k);
            add(root,x,y,k);
        }
        else if(op==3){
            scanf("%d%d",&x,&y);
            ans=0;
            query(root,x,y);
            printf("%lld\n",ans);
        }
    }
    return 0;
}
